home *** CD-ROM | disk | FTP | other *** search
/ Power Hacker 2003 / Power_Hacker_2003.iso / Exploit and vulnerability / w00w00 / trojans / dcron / database.c next >
Encoding:
C/C++ Source or Header  |  1998-08-13  |  10.8 KB  |  555 lines

  1.  
  2. /*
  3.  * DATABASE.C
  4.  *
  5.  * Copyright 1994 Matthew Dillon (dillon@apollo.west.oic.com)
  6.  * May be distributed under the GNU General Public License
  7.  */
  8.  
  9. #include "defs.h"
  10.  
  11. Prototype void CheckUpdates(void);
  12. Prototype void SynchronizeDir(const char *dirName);
  13. Prototype int TestJobs(time_t t1, time_t t2);
  14. Prototype void RunJobs(void);
  15. Prototype int CheckJobs(void);
  16.  
  17. void SynchronizeFile(const  char *fileName);
  18. void DeleteFile(const char *userName);
  19. char *ParseField(char *userName, char *ary, int modvalue, int off, const char **names, char *ptr);
  20. void FixDayDow(CronLine *line);
  21.  
  22. CronFile *FileBase;
  23.  
  24. const char *DowAry[] = {
  25.     "sun",
  26.     "mon",
  27.     "tue",
  28.     "wed",
  29.     "thu",
  30.     "fri",
  31.     "sat",
  32.  
  33.     "Sun",
  34.     "Mon",
  35.     "Tue",
  36.     "Wed",
  37.     "Thu",
  38.     "Fri",
  39.     "Sat",
  40.     NULL
  41. };
  42.  
  43. const char *MonAry[] = {
  44.     "jan",
  45.     "feb",
  46.     "mar",
  47.     "apr",
  48.     "may",
  49.     "jun",
  50.     "jul",
  51.     "aug",
  52.     "sep",
  53.     "oct",
  54.     "nov",
  55.     "dec",
  56.  
  57.     "Jan",
  58.     "Feb",
  59.     "Mar",
  60.     "Apr",
  61.     "May",
  62.     "Jun",
  63.     "Jul",
  64.     "Aug",
  65.     "Sep",
  66.     "Oct",
  67.     "Nov",
  68.     "Dec",
  69.     NULL
  70. };
  71.  
  72. void
  73. CheckUpdates(void)
  74. {
  75.     FILE *fi;
  76.     char buf[256];
  77.  
  78.     if ((fi = fopen(CRONUPDATE, "r")) != NULL) {
  79.         remove(CRONUPDATE);
  80.         while (fgets(buf, sizeof(buf), fi) != NULL) {
  81.             SynchronizeFile(strtok(buf, " \t\r\n"));
  82.         }
  83.         fclose(fi);
  84.     }
  85. }
  86.  
  87. void
  88. SynchronizeDir(const char *dirName)
  89. {
  90.     /*
  91.      * Attempt to delete the database.  Note that we have to make a copy
  92.      * of the string
  93.      */
  94.  
  95.     for (;;) {
  96.     CronFile *file;
  97.     char *user;
  98.  
  99.     for (file = FileBase; file && file->cf_Deleted; file = file->cf_Next)
  100.         ;
  101.     if (file == NULL)
  102.         break;
  103.     user = strdup(file->cf_User);
  104.     DeleteFile(user);
  105.     free(user);
  106.     }
  107.  
  108.     /*
  109.      * Remove cron update file
  110.      *
  111.      * Re-chdir, in case directory was renamed & deleted, or otherwise
  112.      * screwed up.
  113.      *
  114.      * scan directory and add associated users
  115.      */
  116.  
  117.     remove(CRONUPDATE);
  118.     if (chdir(CDir) < 0) {
  119.         log9("unable to find %s\n", CDir);
  120.         exit(20);
  121.     }
  122.     {
  123.         DIR *dir;
  124.         struct dirent *den;
  125.  
  126.         if ((dir = opendir("."))) {
  127.             while ((den = readdir(dir))) {
  128.                 if (strchr(den->d_name, '.') != NULL)
  129.                     continue;
  130.         if (getpwnam(den->d_name))
  131.             SynchronizeFile(den->d_name);
  132.         else
  133.             log(7, "ignoring %s\n", den->d_name);
  134.             }
  135.             closedir(dir);
  136.         } else {
  137.             log9("Unable to open current dir!\n");
  138.             exit(20);
  139.         }
  140.     }
  141. }
  142.  
  143. void
  144. SynchronizeFile(const char *fileName)
  145. {
  146.     int maxEntries = MAXLINES;
  147.     int maxLines;
  148.     char buf[1024];
  149.  
  150.     if (strcmp(fileName, "root") == 0)
  151.         maxEntries = 65535;
  152.     maxLines = maxEntries * 10;
  153.  
  154.     if (fileName) {
  155.     FILE *fi;
  156.  
  157.     DeleteFile(fileName);
  158.  
  159.         if ((fi = fopen(fileName, "r")) != NULL) {
  160.         struct stat sbuf;
  161.  
  162.         if (fstat(fileno(fi), &sbuf) == 0 && sbuf.st_uid == DaemonUid) {
  163.         CronFile *file = calloc(1, sizeof(CronFile));
  164.         CronLine **pline;
  165.  
  166.         file->cf_User = strdup(fileName);
  167.         pline = &file->cf_LineBase;
  168.  
  169.         while (fgets(buf, sizeof(buf), fi) != NULL && --maxLines) {
  170.             CronLine line;
  171.             char *ptr;
  172.  
  173.             if (buf[0])
  174.             buf[strlen(buf)-1] = 0;
  175.  
  176.             if (buf[0] == 0 || buf[0] == '#' || buf[0] == ' ' || buf[0] == '\t')
  177.             continue;
  178.  
  179.             if (--maxEntries == 0)
  180.                 break;
  181.  
  182.             bzero(&line, sizeof(line));
  183.  
  184.             if (DebugOpt)
  185.             log9("User %s Entry %s\n", fileName, buf);
  186.  
  187.             /*
  188.              * parse date ranges
  189.              */
  190.  
  191.             ptr = ParseField(file->cf_User, line.cl_Mins, 60, 0, NULL, buf);
  192.             ptr = ParseField(file->cf_User, line.cl_Hrs,  24, 0, NULL, ptr);
  193.             ptr = ParseField(file->cf_User, line.cl_Days, 32, 0, NULL, ptr);
  194.             ptr = ParseField(file->cf_User, line.cl_Mons, 12, -1, MonAry, ptr);
  195.             ptr = ParseField(file->cf_User, line.cl_Dow, 7, 0, DowAry, ptr);
  196.  
  197.             /*
  198.              * check failure
  199.              */
  200.  
  201.             if (ptr == NULL)
  202.             continue;
  203.  
  204.             /*
  205.              * fix days and dow - if one is not * and the other
  206.              * is *, the other is set to 0, and vise-versa
  207.              */
  208.  
  209.             FixDayDow(&line);
  210.  
  211.             *pline = calloc(1, sizeof(CronLine));
  212.             **pline = line;
  213.  
  214.             /*
  215.              * copy command
  216.              */
  217.  
  218.             (*pline)->cl_Shell = strdup(ptr);
  219.  
  220.             if (DebugOpt) {
  221.             log9("    Command %s\n", ptr);
  222.             }
  223.  
  224.             pline = &((*pline)->cl_Next);
  225.         }
  226.         *pline = NULL;
  227.  
  228.         file->cf_Next = FileBase;
  229.         FileBase = file;
  230.  
  231.         if (maxLines == 0 || maxEntries == 0)
  232.             log9("Maximum number of lines reached for user %s\n", fileName);
  233.         }
  234.         fclose(fi);
  235.     } 
  236.     }
  237. }
  238.  
  239. char *
  240. ParseField(char *user, char *ary, int modvalue, int off, const char **names, char *ptr)
  241. {
  242.     char *base = ptr;
  243.     int n1 = -1;
  244.     int n2 = -1;
  245.  
  246.     if (base == NULL)
  247.         return(NULL);
  248.  
  249.     while (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
  250.         int skip = 0;
  251.  
  252.     /*
  253.      * Handle numeric digit or symbol or '*'
  254.      */
  255.  
  256.         if (*ptr == '*') {
  257.         n1 = 0;            /* everything will be filled */
  258.         n2 = modvalue - 1;
  259.             skip = 1;
  260.             ++ptr;
  261.     } else if (*ptr >= '0' && *ptr <= '9') {
  262.         if (n1 < 0)
  263.             n1 = strtol(ptr, &ptr, 10) + off;
  264.         else
  265.             n2 = strtol(ptr, &ptr, 10) + off;
  266.         skip = 1;
  267.     } else if (names) {
  268.         int i;
  269.  
  270.         for (i = 0; names[i]; ++i) {
  271.             if (strncmp(ptr, names[i], strlen(names[i])) == 0) {
  272.                 break;
  273.             }
  274.         }
  275.         if (names[i]) {
  276.             ptr += strlen(names[i]);
  277.             if (n1 < 0)
  278.                 n1 = i;
  279.         else
  280.             n2 = i;
  281.         skip = 1;
  282.         }
  283.     }
  284.  
  285.     /*
  286.      * handle optional range '-'
  287.      */
  288.  
  289.     if (skip == 0) {
  290.         log9("failed user %s parsing %s\n", user, base);
  291.         return(NULL);
  292.     }
  293.     if (*ptr == '-' && n2 < 0) {
  294.         ++ptr;
  295.         continue;
  296.     }
  297.  
  298.     /*
  299.      * collapse single-value ranges, handle skipmark, and fill
  300.      * in the character array appropriately.
  301.      */
  302.  
  303.     if (n2 < 0)
  304.         n2 = n1;
  305.  
  306.     if (*ptr == '/')
  307.         skip = strtol(ptr + 1, &ptr, 10);
  308.  
  309.     /*
  310.      * fill array, using a failsafe is the easiest way to prevent
  311.      * an endless loop
  312.      */
  313.  
  314.         {
  315.             int s0 = 1;
  316.         int failsafe = 1024;
  317.  
  318.             --n1;
  319.             do {
  320.                 n1 = (n1 + 1) % modvalue;
  321.  
  322.             if (--s0 == 0) {
  323.             ary[n1 % modvalue] = 1;
  324.             s0 = skip;
  325.         }
  326.         } while (n1 != n2 && --failsafe);
  327.  
  328.         if (failsafe == 0) {
  329.         log9("failed user %s parsing %s\n", user, base);
  330.         return(NULL);
  331.         }
  332.     }
  333.     if (*ptr != ',')
  334.         break;
  335.     ++ptr;
  336.     n1 = -1;
  337.     n2 = -1;
  338.     }
  339.  
  340.     if (*ptr != ' ' && *ptr != '\t' && *ptr != '\n') {
  341.     log9("failed user %s parsing %s\n", user, base);
  342.         return(NULL);
  343.     }
  344.  
  345.     while (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')
  346.         ++ptr;
  347.  
  348.     if (DebugOpt) {
  349.         int i;
  350.  
  351.         for (i = 0; i < modvalue; ++i)
  352.             log(5, "%d", ary[i]);
  353.     log(5, "\n");
  354.     }
  355.  
  356.     return(ptr);
  357. }
  358.  
  359. void
  360. FixDayDow(CronLine *line)
  361. {
  362.     short i;
  363.     short weekUsed = 0;
  364.     short daysUsed = 0;
  365.  
  366.     for (i = 0; i < arysize(line->cl_Dow); ++i) {
  367.         if (line->cl_Dow[i] == 0) {
  368.             weekUsed = 1;
  369.             break;
  370.     }
  371.     }
  372.     for (i = 0; i < arysize(line->cl_Days); ++i) {
  373.         if (line->cl_Days[i] == 0) {
  374.             daysUsed = 1;
  375.             break;
  376.     }
  377.     }
  378.     if (weekUsed && !daysUsed) {
  379.         memset(line->cl_Days, 0, sizeof(line->cl_Days));
  380.     }
  381.     if (daysUsed && !weekUsed) {
  382.         memset(line->cl_Dow, 0, sizeof(line->cl_Dow));
  383.     }
  384. }
  385.  
  386. /*
  387.  *  DeleteFile() - delete user database
  388.  *
  389.  *  Note: multiple entries for same user may exist if we were unable to 
  390.  *  completely delete a database due to running processes.
  391.  */
  392.  
  393. void
  394. DeleteFile(const char *userName)
  395. {
  396.     CronFile **pfile = &FileBase;
  397.     CronFile *file;
  398.  
  399.     while ((file = *pfile) != NULL) {
  400.         if (strcmp(userName, file->cf_User) == 0) {
  401.             CronLine **pline = &file->cf_LineBase;
  402.             CronLine *line;
  403.  
  404.             file->cf_Running = 0;
  405.             file->cf_Deleted = 1;
  406.  
  407.             while ((line = *pline) != NULL) {
  408.                 if (line->cl_Pid > 0) {
  409.                     file->cf_Running = 1;
  410.                     pline = &line->cl_Next;
  411.         } else {
  412.             *pline = line->cl_Next;
  413.             free(line->cl_Shell);
  414.             free(line);
  415.         }
  416.         }
  417.         if (file->cf_Running == 0) {
  418.         *pfile = file->cf_Next;
  419.         free(file->cf_User);
  420.         free(file);
  421.         } else {
  422.             pfile = &file->cf_Next;
  423.         }
  424.         } else {
  425.             pfile = &file->cf_Next;
  426.         }
  427.     }
  428. }
  429.  
  430. /*
  431.  * TestJobs()
  432.  *
  433.  * determine which jobs need to be run.  Under normal conditions, the
  434.  * period is about a minute (one scan).  Worst case it will be one
  435.  * hour (60 scans).
  436.  */
  437.  
  438. int
  439. TestJobs(time_t t1, time_t t2)
  440. {
  441.     short nJobs = 0;
  442.     time_t t;
  443.  
  444.     /*
  445.      * Find jobs > t1 and <= t2
  446.      */
  447.  
  448.     for (t = t1 - t1 % 60; t <= t2; t += 60) {
  449.     if (t > t1) {
  450.         struct tm *tp = localtime(&t);
  451.         CronFile *file;
  452.         CronLine *line;
  453.  
  454.         for (file = FileBase; file; file = file->cf_Next) {
  455.         if (DebugOpt)
  456.             log(5, "FILE %s:\n", file->cf_User);
  457.         if (file->cf_Deleted)
  458.             continue;
  459.         for (line = file->cf_LineBase; line; line = line->cl_Next) {
  460.             if (DebugOpt)
  461.                 log(5, "    LINE %s\n", line->cl_Shell);
  462.             if (line->cl_Mins[tp->tm_min] &&
  463.                 line->cl_Hrs[tp->tm_hour] &&
  464.                 (line->cl_Days[tp->tm_mday] || line->cl_Dow[tp->tm_wday]) &&
  465.                 line->cl_Mons[tp->tm_mon]
  466.             ) {
  467.                 if (DebugOpt)
  468.                     log(5, "    JobToDo: %d %s\n", line->cl_Pid, line->cl_Shell);
  469.                 if (line->cl_Pid > 0) {
  470.                     log(8, "    process already running: %s %s\n", 
  471.                         file->cf_User,
  472.                         line->cl_Shell
  473.                     );
  474.                 } else if (line->cl_Pid == 0) {
  475.                     line->cl_Pid = -1;
  476.                     file->cf_Ready = 1;
  477.                     ++nJobs;
  478.                 }
  479.             }
  480.         }
  481.         }
  482.     }
  483.     }
  484.     return(nJobs);
  485. }
  486.  
  487. void
  488. RunJobs(void)
  489. {
  490.     CronFile *file;
  491.     CronLine *line;
  492.  
  493.     for (file = FileBase; file; file = file->cf_Next) {
  494.     if (file->cf_Ready) {
  495.         file->cf_Ready = 0;
  496.  
  497.         for (line = file->cf_LineBase; line; line = line->cl_Next) {
  498.         if (line->cl_Pid < 0) {
  499.  
  500.             RunJob(file, line);
  501.  
  502.             log(8, "USER %s pid %3d cmd %s\n",
  503.             file->cf_User,
  504.             line->cl_Pid,
  505.             line->cl_Shell
  506.             );
  507.             if (line->cl_Pid < 0)
  508.                 file->cf_Ready = 1;
  509.             else if (line->cl_Pid > 0)
  510.             file->cf_Running = 1;
  511.         }
  512.         }
  513.     }
  514.     }
  515. }
  516.  
  517. /*
  518.  * CheckJobs() - check for job completion
  519.  *
  520.  * Check for job completion, return number of jobs still running after
  521.  * all done.
  522.  */
  523.  
  524. int
  525. CheckJobs(void)
  526. {
  527.     CronFile *file;
  528.     CronLine *line;
  529.     int nStillRunning = 0;
  530.  
  531.     for (file = FileBase; file; file = file->cf_Next) {
  532.     if (file->cf_Running) {
  533.         file->cf_Running = 0;
  534.  
  535.         for (line = file->cf_LineBase; line; line = line->cl_Next) {
  536.         if (line->cl_Pid > 0) {
  537.             int status;
  538.             int r = wait4(line->cl_Pid, &status, WNOHANG, NULL);
  539.  
  540.             if (r < 0 || r == line->cl_Pid) {
  541.                 EndJob(file, line);
  542.                 if (line->cl_Pid)
  543.                 file->cf_Running = 1;
  544.             } else if (r == 0) {
  545.                 file->cf_Running = 1;
  546.             }
  547.         }
  548.         }
  549.     }
  550.     nStillRunning += file->cf_Running;
  551.     }
  552.     return(nStillRunning);
  553. }
  554.  
  555.